import java.awt.Color;
import java.util.ArrayList;
import javax.swing.JLabel;
//Base class of different sort algorithm classes
abstract class SortAlgorithm<T extends Comparable<T>> {
    protected ArrayList<T> m_list; 
    private StopWatch m_timer;
    private long m_accumulatedTime;
    private int m_nbrCalls, m_maxItToPrint;
    protected JLabel m_listLabel;
    protected JLabel m_timeLabel;
    protected JLabel m_avTimeLabel;
    protected JLabel m_statusLabel;
    SortAlgorithm(JLabel listLabel, JLabel timeLabel, JLabel averageTimeLabel, JLabel statusLabel) {
        m_list = new ArrayList<T>();
        m_timer = new StopWatch();
        m_accumulatedTime = 0;
        m_nbrCalls = 0;
        m_listLabel = listLabel;
        m_timeLabel = timeLabel;
        m_avTimeLabel = averageTimeLabel;
        m_statusLabel = statusLabel;
        m_maxItToPrint = 31; //Suitable for 3-numbers integers 
    };
    public void setMaxNItemsToPrint(int maxItToPrint) { m_maxItToPrint = maxItToPrint; } 
    public void printList() {
        String tempString = "Too many items to show the list";
        if (m_list.size() <= m_maxItToPrint) {
            tempString = "";
            for (int i = 0; i < m_list.size(); i++) tempString += m_list.get(i) + "  ";
        }
	m_listLabel.setText(tempString);
    }
    public void printSortTime(JLabel label) {
        label.setText(String.valueOf(m_timer.getElapsedTime()+" ms"));
    }
    public void printAverageSortTime(JLabel label) {
        if (m_nbrCalls == 0) { label.setText("0");
        } else { label.setText(String.valueOf(m_accumulatedTime/m_nbrCalls)+" ms"); }
    }
    public void fill(T val) { m_list.add(val); }
    public Long sortAndBenchmark() {
        m_timer.reset();
        m_timer.start();
        sort();
        m_timer.stop();
        m_nbrCalls++;
        m_accumulatedTime += m_timer.getElapsedTime();
        return m_timer.getElapsedTime();
    }
    public Long sortBenchmarkAndShow() {
        sortAndBenchmark();
        printAll();
        return m_timer.getElapsedTime();
    }
    public void printAll() {
        printList();
        printSortTime(m_timeLabel);
        printAverageSortTime(m_avTimeLabel);
    }
    public void clearList() { 
        m_list.clear();
        setEmpty();
    }
    public void reset() {
        m_list.clear();
        m_timer.reset();
        m_accumulatedTime = 0;
        m_nbrCalls = 0;
        printAll();
    }
    
    //The actual sort method, to be overriden
    abstract protected void sort(); 
    
    //For Checking
    public boolean isSorted() {
        for (int i = 1; i < m_list.size(); i++) if (less(i, i-1)) return false;
        return true;
    }

    //Status methods
    public void setEmpty() {
        m_statusLabel.setText("EMPTY");
        m_statusLabel.setForeground(Color.BLACK);
    }
    public void setShuffled() {
        m_statusLabel.setText("SHUFFLED");
        m_statusLabel.setForeground(Color.BLUE);
    }
    public void setSorting() {
        m_statusLabel.setText("SORTING");
        m_statusLabel.setForeground(Color.BLACK);
    }
    public void setDone() {
        m_statusLabel.setText("DONE");
        m_statusLabel.setForeground(Color.MAGENTA);
    }
    public void setChecking() {
        m_statusLabel.setText("CHECKING");
        m_statusLabel.setForeground(Color.ORANGE);
    }
    public void setSorted() {
        m_statusLabel.setText("SORTED");
        m_statusLabel.setForeground(Color.green);
    }
    public void setFailed() {
        m_statusLabel.setText("FAILED");
        m_statusLabel.setForeground(Color.RED);
    }
    
    
    //Handy methods
    protected void swapElements(int i, int j) {  
        m_list.set(i, m_list.set(j, m_list.get(i)));
    }
    protected boolean less(int i, int j) {
        return ( m_list.get(i).compareTo(m_list.get(j)) < 0 );
    }
    protected boolean less(int i, T y) {
        return ( m_list.get(i).compareTo(y) < 0 );
    }
    protected boolean less(T x, T y) {
        return ( x.compareTo(y) < 0 );
    }
    protected boolean greater(int i, int j) {
        return ( m_list.get(i).compareTo(m_list.get(j)) > 0 );
    }
    protected boolean greater(int i, T y) {
        return ( m_list.get(i).compareTo(y) > 0 );
    }
    protected boolean greater(T x, T y) {
        return ( x.compareTo(y) > 0 );
    }
 
}
